package com.market2.session;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.jboss.ejb3.annotation.RemoteBinding;

import com.market2.dto.NegociationDto;
import com.market2.dto.NegociationEnchereDto;
import com.market2.dto.NegociationPrixFixDto;
import com.market2.dto.OperationDto;
import com.market2.model.Contrat;
import com.market2.model.Investisseur;
import com.market2.model.Negociation;
import com.market2.model.NegociationEnchere;
import com.market2.model.NegociationPrixFix;
import com.market2.model.Operation;
import com.market2.utils.EntityManagerThreadLocal;
import com.market2.utils.Globals;
import com.market2.utils.StatusOperation;
import com.market2.utils.converter.ConverterUtil;

/**
 * Session Bean implementation class OperationBeanManager
 */

@Stateless @RemoteBinding(jndiBinding="Market2EAR/OperationManager/remote")
public class OperationManager implements OperationManagerRemote
{
	@PersistenceContext(unitName=Globals.PERSISTENCE_UNIT_NAME)
	private EntityManager entityManager;
	
	@PostConstruct
	void init() {
		EntityManagerThreadLocal.set(entityManager);
	}

	@Override
	public List<OperationDto> getBestOfAchats(String societe, Integer nbOffres)
	{
		Query query = entityManager.createQuery("from Operation operation where operation.contrat.societe.nom = :nomSociete and operation.vendeur is null");
		query.setParameter("nomSociete", societe);
		query.setMaxResults(nbOffres);
		
		@SuppressWarnings("unchecked")
		List<Operation> operations = (List<Operation>) query.getResultList();
		return ConverterUtil.convertTo(operations, OperationDto.class);
	}
	
	@Override
	public List<OperationDto> getBestOfVentes(String societe, Integer nbOffres)
	{
		Query query = entityManager.createQuery("from Operation operation where operation.contrat.societe.nom = :nomSociete and operation.acheteur is null");
		query.setParameter("nomSociete", societe);
		query.setMaxResults(nbOffres);
		
		@SuppressWarnings("unchecked")
		List<Operation> operations = (List<Operation>) query.getResultList();
		return ConverterUtil.convertTo(operations, OperationDto.class);
	}

	@Override
	public List<OperationDto> getOperationByCriteria(Map<String, Object> properties)
	{
		if(properties == null) {
			return new ArrayList<OperationDto>();
		}
		
		CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
		CriteriaQuery<Operation> criteriaQuery = criteriaBuilder.createQuery(Operation.class);
		Root<Operation> from = criteriaQuery.from(Operation.class);
		
		for(String prop : properties.keySet())
		{
			Object val = properties.get(prop);
			
			Path<Operation> param = from.get(prop);
			Predicate condition = criteriaBuilder.equal(param, val);
			criteriaQuery.where(criteriaBuilder.and(condition));
		}
		
		CriteriaQuery<Operation> select = criteriaQuery.select(from);
		TypedQuery<Operation> typedQuery = entityManager.createQuery(select);

		List<Operation> queryResult = typedQuery.getResultList();
		List<OperationDto> result = ConverterUtil.convertTo(queryResult, OperationDto.class);
		
		return result;
	}

	@Override
	public void demanderAchat(String acheteur, Integer contrat, Double prix)
	{
		Negociation nego = new NegociationPrixFix(); 
		nego.setPrix(prix);
		
		Contrat c = entityManager.find(Contrat.class, contrat);
		Investisseur inv = entityManager.find(Investisseur.class, acheteur);
		
		Operation operation = new Operation();
		operation.setStatus(StatusOperation.OUVERT);
		operation.setNegociation(nego);
		operation.setVendeur(null);
		operation.setAcheteur(inv);
		operation.setContrat(c);
		
		entityManager.persist(operation);
		entityManager.flush();
	}

	@Override
	public void mettreEnVente(String vendeur, NegociationDto negociation, Integer contrat)
	{
		Negociation newNegociation = null;
		
		if(negociation instanceof NegociationPrixFixDto)
		{
			NegociationPrixFixDto dto = (NegociationPrixFixDto) negociation;
			NegociationPrixFix nego = new NegociationPrixFix();
			
			nego.setNumero(dto.getNumero());
			nego.setPrix(dto.getPrix());
			
			newNegociation = nego;
		}
		else
		{
			if(negociation instanceof NegociationEnchereDto)
			{
				NegociationEnchereDto dto = (NegociationEnchereDto) negociation;
				NegociationEnchere nego = new NegociationEnchere();
				
				nego.setNumero(dto.getNumero());
				nego.setPrix(dto.getPrix());
				nego.setDateDebut(dto.getDateDebut());
				nego.setDateFin(dto.getDateFin());
				
				newNegociation = nego;
			}
			else {
				return;
			}
		}
		
		Contrat c = entityManager.find(Contrat.class, contrat);
		Investisseur inv = entityManager.find(Investisseur.class, vendeur);
		
		Operation operation = new Operation();
		operation.setStatus(StatusOperation.OUVERT);
		operation.setNegociation(newNegociation);
		operation.setVendeur(inv);
		operation.setAcheteur(null);
		operation.setContrat(c);
		
		entityManager.persist(operation);
	}

	@Override
	public void finaliserAchat(Integer achat, String acheteur, Double prix)
	{
		Operation opAchat = entityManager.find(Operation.class, achat);
		Investisseur investisseur = entityManager.find(Investisseur.class, acheteur);
		
		opAchat.setStatus(StatusOperation.CONCLU);
		opAchat.setAcheteur(investisseur);
		
		if(opAchat.getNegociation() instanceof NegociationEnchere) {
			opAchat.getNegociation().setPrix(prix);
		}
		
		opAchat.getContrat().setTitulaire(investisseur);
	}

	@Override
	public void finaliserVente(Integer vente, String vendeur, Double prix)
	{
		Operation opVente = entityManager.find(Operation.class, vente);
		Investisseur investisseur = entityManager.find(Investisseur.class, vendeur);
		
		opVente.setStatus(StatusOperation.CONCLU);
		opVente.setVendeur(investisseur);
		
		if(opVente.getNegociation() instanceof NegociationEnchere) {
			opVente.getNegociation().setPrix(prix);
		}
		
		opVente.getContrat().setTitulaire(opVente.getAcheteur());
	}
}
